package models;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.persistence.*;

import common.TVRageRequest;
import common.iMDBRequest;

import play.db.jpa.JPA;
import play.db.jpa.Model;

@Entity
public class Serie extends Model {
	
	
	
	/* Attributes */

	@Column(nullable = false)
	private String name;
	
	private Integer runtime;
	
	private String channel;
	
	private Date airTime;
	
	private String airDay;
	
	private String timezone;
	
	private String director;
	
	private String poster;
	
	private String country;
	
	private String startDate;
	
	private String endDate;
	
	private long tvrageid;

	private String mdb;
	
	

	@Lob
	private String summary;
	

	private float avgRate;

	private int numOfFollowers;
	

	private String casts;

	
	
	@ElementCollection
	private List<String> genres;

	

	@OneToMany(mappedBy="serie", cascade=CascadeType.ALL)
	private List<Rate> rateList;

	@ManyToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
	private List<User> followers;

	@OneToMany(fetch=FetchType.LAZY, mappedBy="serie", cascade=CascadeType.ALL)
	private List<Topic> topicList;	

	@OneToMany(fetch=FetchType.LAZY, mappedBy="serie", cascade=CascadeType.ALL)
	private List<Video> videoList;

	@OneToMany(fetch=FetchType.LAZY, mappedBy="serie", cascade=CascadeType.ALL)
	private List<Episode> episodeList;

	@OneToMany(fetch=FetchType.LAZY, mappedBy="serie", cascade=CascadeType.ALL)
	private List<CommentSerie> commentList;


	
	
	/* Constructor */
	
	public Serie(String name, Integer runtime, String channel, Date airTime,
			String airDay, String timezone, String director, String poster,
			String country, String startDate, String endDate, long tvrageid,
			String mdb, String summary,	String casts, List<String> genres) {
		super();
		this.name = name;
		this.runtime = runtime;
		this.channel = channel;
		this.airTime = airTime;
		this.airDay = airDay;
		this.timezone = timezone;
		this.director = director;
		this.poster = poster;
		this.country = country;
		this.startDate = startDate;
		this.endDate = endDate;
		this.tvrageid = tvrageid;
		this.mdb = mdb;
		this.summary = summary;
		this.avgRate = 0;
		this.numOfFollowers = 0;
		this.casts = casts;
		this.genres = genres;
		this.rateList = new ArrayList<Rate>();
		this.followers = new ArrayList<User>();
		this.topicList = new ArrayList<Topic>();
		this.videoList = new ArrayList<Video>();
		this.episodeList = new ArrayList<Episode>();
		this.commentList = new ArrayList<CommentSerie>();
	}
	



	/* Getters & Setters */

	public Integer getRuntime() {
		return runtime;
	}

	public void setRuntime(Integer runtime) {
		this.runtime = runtime;
	}

	public String getChannel() {
		return channel;
	}

	public void setChannel(String channel) {
		this.channel = channel;
	}

	public Date getAirTime() {
		return airTime;
	}

	public void setAirTime(Date airTime) {
		this.airTime = airTime;
	}

	public String getAirDay() {
		return airDay;
	}

	public void setAirDay(String airDay) {
		this.airDay = airDay;
	}

	public String getTimezone() {
		return timezone;
	}

	public void setTimezone(String timezone) {
		this.timezone = timezone;
	}

	public List<String> getGenres() {
		return genres;
	}

	public void setGenres(List<String> genres) {
		this.genres = genres;
	}

	public List<Video> getVideoList() {
		return videoList;
	}

	public void setVideoList(List<Video> videoList) {
		this.videoList = videoList;
	}

	public List<Episode> getEpisodeList() {
		return episodeList;
	}

	public void setEpisodeList(List<Episode> episodeList) {
		this.episodeList = episodeList;
	}

	public void setCasts(String casts) {
		this.casts = casts;
	}

	public void setRateList(List<Rate> rateList) {
		this.rateList = rateList;
	}

	public void setCommentList(List<CommentSerie> commentList) {
		this.commentList = commentList;
	}

	public void setFollowers(List<User> followers) {
		this.followers = followers;
	}

	public float getAvgRate() {
		return avgRate;
	}

	public void setAvgRate(float avgRate) {
		this.avgRate = avgRate;
	}

	public List<Rate> getRateList() {
		return rateList;
	}

	public List<CommentSerie> getCommentList() {
		return commentList;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setRateList(ArrayList<Rate> rateList) {
		this.rateList = rateList;
	}

	public String getDirector() {
		return director;
	}

	public void setDirector(String director) {
		this.director = director;
	}

	public List<User> getFollowers() {
		return followers;
	}

	public void setFollowers(ArrayList<User> followers) {
		this.followers = followers;
	}

	public String getCasts() {
		return casts;
	}

	public List<Topic> getTopicList() {
		return topicList;
	}

	public void setTopicList(List<Topic> topicList) {
		this.topicList = topicList;
	}

	public long getTvrageid() {
		return tvrageid;
	}

	public void setTvrageid(long tvrageid) {
		this.tvrageid = tvrageid;
	}

	public String getSummary() {
		return summary;
	}

	public void setSummary(String summary) {
		this.summary = summary;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public String getPoster() {
		return poster;
	}

	public void setPoster(String poster) {
		this.poster = poster;
	}
	
	public int getNumOfFollowers() {
		return numOfFollowers;
	}

	public void setNumOfFollowers(int numOfFollowers) {
		this.numOfFollowers = numOfFollowers;
	}
		
	public String getMdb() {
		return mdb;
	}

	public void setMdb(String mdb) {
		this.mdb = mdb;
	}
	
	public String getStartDate() {
		return startDate;
	}

	public void setStartDate(String startDate) {
		this.startDate = startDate;
	}

	public String getEndDate() {
		return endDate;
	}

	public void setEndDate(String endDate) {
		this.endDate = endDate;
	}

	
	
	
	


	
	
	/* Search Series */

	public static List<Serie> searchSeries(String param, String type) {

		if(param != null) {
			param = "%" + param.toString() + "%";
			param = param.toLowerCase();
		}

		if(type == null || type.equals("following")){
			return (Serie.find("LOWER(name) like ? order by numOfFollowers desc", param).fetch());
		}

		else {
			return (Serie.find("LOWER(name) like ? order by avgRate desc", param).fetch());
		}
	}
	
	
	
	/* Return all Series */
	
	public static List<Serie> getAllSeries(){
		return Serie.findAll();	
	}
	
	
	
	
	/* Get All Series starting with a Character with Type */
	
	public static List<Serie> getAllSpecificCharSeries(String param, String type) {

		if(param != null)
			param = param.toLowerCase();

		if(type == null || type.equals("following") ){
			return (Serie.getSeriesOrderByFollowers(param));
		}
		else 
			return (Serie.getSeriesOrderByRate(param));

	}



	
	/* Get All Series OrderBy Followers */

	public static List<Serie> getSeriesOrderByFollowers(String param) {
		
		if(param == null) {
			return (Serie.find("order by numOfFollowers desc").fetch());			
		}
		
		else {
			Query query = JPA.em().createQuery("select s from Serie s where LOWER(s.name) like '"
					+ param + "%' order by numOfFollowers desc");
			
			return query.getResultList();
		}
		

	}
	
	
	public static List<Serie> getSeriesOrderByFollowersTopTen() {

			return (Serie.find("order by numOfFollowers desc").from(0).fetch(10));	
			
	}
	
	public static List<Serie> getSeriesOrderByRateTopTen() {
		
			return (Serie.find("order by avgRate desc").from(0).fetch(10));				
	}

	
	
	/* Get All Series OrderBy Rate */

	public static List<Serie> getSeriesOrderByRate(String param) {
		
		if(param == null) {
			return (Serie.find("order by avgRate desc").fetch());
		}
		
		else {
			Query query = JPA.em().createQuery("select s from Serie s where LOWER(s.name) like '"
					+ param + "%' order by avgRate desc");
			
			return query.getResultList();
		}
	}
	
	
	
	
	/* Get Topics OrderBy Type */

	public static List<Topic> getAllTopicOrder(long id, String type) {


		if(type == null || type.equals("comments") ){
			return (Serie.getTopicOrderByComments(id));
		}
		else 
			return (Serie.getTopicOrderByDate(id));

	}

	
	
	/* Get Topics OrderBy Date */
	
	public static List<Topic> getTopicOrderByDate(long id) {
		return (Topic.find("serie.id = ? order by creationDate desc", id).fetch());
	}


	
	
	
	/* Get Topics OrderBy Comment */
	public static List<Topic> getTopicOrderByComments(long id) {
		return (Topic.find("serie.id = ? order by commentNum desc", id).fetch());
	}

	

	
	/* Add a Follower */
	
	public void addFollower(User user){
		if(!followers.contains(user)){
			followers.add(user);
			this.numOfFollowers++;
		}
	}


	
	/* Remove a Follower */
	
	public void removeFollower(User user){
		if(followers.contains(user)){
			followers.remove(user);
			this.numOfFollowers--;
		}
	}




	/* Add new Comment */

	public Serie addComment(User user, String comment) {

		CommentSerie newComment = new CommentSerie(user, comment, this);
		this.commentList.add(newComment);
		this.save();
		return this;
	}



	/* Add a Rate */

	public void addRate(Rate rate){
		rateList.add(rate);
		calcAvgRate();
	}
	
	
	/* Remove a Rate */

	public void removeRate(Rate Rate) {
		rateList.remove(Rate);
		calcAvgRate();
	}
	
	
	

	/* Calculate Avarage Rate */

	public void calcAvgRate(){

		float avgRate = 0;

		if (getRateList().size() != 0) {

			for (Rate rate : getRateList())
				avgRate += rate.getRate();

			avgRate = avgRate / getRateList().size();
		}

		avgRate = (float) (Math.round(avgRate*100.0)/100.0);
		setAvgRate(avgRate);
	}
	
	
	
	
	/* Fill Information of Series from External Sources */
	
	public void fillInfo() {
		TVRageRequest.fillSeries(this);
		//iMDBRequest.fillSeries(this);
	}
	

	
	
	/* Add new Episode */
	
	public void addEpisode(Episode e) {
		this.episodeList.add(e);
		e.save();
	}
	
	
	/* Get AirTime */
	
	public String getFormattedAirTime() {
        String formattedDate = null;
        
        if (airTime != null) {
    		SimpleDateFormat formatter = new SimpleDateFormat("mm:ss");
    		formattedDate = formatter.format(airTime);
        }
        
		return formattedDate;
	}
	
	
	/* Get UnEnded Series */
	
	public static List<Serie> getSeriesNotEnded() {

		Query query = JPA.em().createQuery("select s from Serie s where s.endDate is NULL");
		return query.getResultList();
		
	}
}
